using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine.UIElements;

namespace DA.AnimGraph.Editor {

    [NodeMenuItem(typeof(AGANode_LayerBlend), "Layer Blend")]
    internal class NodeView_LayerBlend : NodeViewBase {
        public override string titleText => "Layer Blend";

        protected override NodeViewInspectorSourceBase dataSource => inspectorData;
        NodeViewInspector_LayerBlend inspectorData;

        internal override void Init(AGAHandle_Node handle, AnimGraphView graphView, AGEEnvironment ageContext) {
            inspectorData = new NodeViewInspector_LayerBlend();
            inspectorData.SetHandle(handle);
            base.Init(handle, graphView, ageContext);
        }

    }

    internal class NodeViewInspector_LayerBlend : NodeViewInspectorSourceBase {

        /*[InspectorField(isList: true)]*/
        public List<AGAFieldModel_Layer> layerDescs;
        [InspectorField(tag: "inputPort", isList: true)] public List<AGAFieldModel_InputPort> inputPort;

        protected override void LoadFromModel() {
            var model = handleKeeper.handle.data.modelProperty as AGANodeModel_LayerBlend;
            layerDescs = model.layerDescs;

            var bNode = handleKeeper.handle.data as AGANode_BlendBase;
            inputPort = new List<AGAFieldModel_InputPort>(bNode.inputChildren.Count);
            for (int i = 0; i < bNode.inputChildren.Count; i++) {
                inputPort.Add(new AGAFieldModel_InputPort(bNode.inputNames[i], bNode.inputChildren[i]));
            }
        }

        protected override void SaveToModel() {
            // 全量覆盖保存输入端口
            var newInputs = inputPort.Select(m => (m.portUuid, m.name)).ToList();
            handleKeeper.handle.WriteAllInput(newInputs);
        }

        protected override VisualElement CustomizeField(string name, InspectorFieldAttribute fieldAttribute, FieldInfo fieldInfo, AGEContext ageContext, Action inspectorChangeCallback) {
            if (fieldAttribute.tag == "inputPort") {
                //return BuildInputPortList(name, fieldAttribute, fieldInfo, ageContext, inspectorChangeCallback);
                return BuildInputPortList2(name, fieldAttribute, fieldInfo, ageContext, inspectorChangeCallback);
            }
            return base.CustomizeField(name, fieldAttribute, fieldInfo, ageContext, inspectorChangeCallback);
        }

        private VisualElement BuildInputPortList2(string name, InspectorFieldAttribute fieldAttribute, FieldInfo fieldInfo, AGEContext ageContext, Action inspectorChangeCallback) {
            var listView = new ListViewAGE() {
                title = name,
                enableCountController = true,
                itemsSource = inputPort,
            };

            listView.makeItem = () => {
                var w = new FoldoutWrapper();
                w.upButtonClicked += (index) => {
                    (inputPort[index], inputPort[index - 1]) = (inputPort[index - 1], inputPort[index]);
                    index = index - 1;
                    (layerDescs[index], layerDescs[index - 1]) = (layerDescs[index - 1], layerDescs[index]);
                    listView.Rebuild();
                    inspectorChangeCallback?.Invoke();
                };
                w.downButtonClicked += (index) => {
                    (inputPort[index], inputPort[index + 1]) = (inputPort[index + 1], inputPort[index]);
                    index = index - 1;
                    (layerDescs[index], layerDescs[index + 1]) = (layerDescs[index + 1], layerDescs[index]);
                    listView.Rebuild();
                    inspectorChangeCallback?.Invoke();
                };
                w.deleteButtonClicked += (index) => {
                    layerDescs.RemoveAt(index - 1);
                    inputPort.RemoveAt(index);
                    listView.Rebuild();
                    inspectorChangeCallback?.Invoke();
                };
                var l = new InspectorField_LayerBlendLayer();
                return (l, w);
            };

            listView.bindItem = (element, wrapper, index) => {
                VisualElement nameInputField = null;
                if (element is InspectorField_LayerBlendLayer field) {
                    field.portField.Init(null, inputPort[index], ageContext, inspectorChangeCallback);
                    nameInputField = field.portField;
                    field.EnableLayerField(index > 0);
                    if (index > 0) {
                        field.layerField.Init(null, layerDescs[index - 1], ageContext, inspectorChangeCallback);
                    }
                }
                if (wrapper is FoldoutWrapper w) {
                    w.index = index;
                    w.text = $"[{index}]";
                    w.enableUp = index > 1;
                    w.enableDown = index > 0 && index < inputPort.Count - 1;
                    w.enableDelete = index != 0 && inputPort.Count > 2;
                    w.SetToTitle(nameInputField);
                }
            };

            listView.addButtonClicked = () => {
                layerDescs.Add(new AGAFieldModel_Layer());
                inputPort.Add(new AGAFieldModel_InputPort("new port"));
                listView.Rebuild();
                inspectorChangeCallback?.Invoke();
            };

            return listView;
        }

        VisualElement BuildInputPortList(string name, InspectorFieldAttribute fieldAttribute, FieldInfo fieldInfo, AGEContext ageContext, Action inspectorChangeCallback) {
            ListView listView = new ListView() {
                name = name,
                headerTitle = name,
                reorderable = true,
                reorderMode = ListViewReorderMode.Animated,
                selectionType = SelectionType.Single,
                showAlternatingRowBackgrounds = AlternatingRowBackground.All,
                showFoldoutHeader = true,
                // showAddRemoveFooter = true,
                showBorder = true,
            };
            listView.itemsSource = inputPort;
            listView.itemIndexChanged += (oldIndex, newIndex) => {
                listView.Rebuild();
                inspectorChangeCallback?.Invoke();
            };
            listView.makeItem = () => {
                var field = new InspectorField_InputPort();
                return field;
            };
            listView.bindItem = (element, index) => {
                if (element is InspectorField_InputPort field) {
                    field.Init(null, inputPort[index], ageContext, inspectorChangeCallback);
                }
            };
            listView.itemsAdded += indices => {
                foreach (var index in indices) {
                    var newItem = new AGAFieldModel_InputPort("new port");
                    inputPort[index] = newItem;
                }
                SaveToModel();
            };
            listView.itemsRemoved += indices => {
                foreach (var index in indices) {
                    handleKeeper.handle.RemoveInput(inputPort[index].portUuid);
                }
            };
            return listView;
        }
    }

    /// <summary>
    /// 包装 InspectorField_Layer，因为要根据情况开关
    /// </summary>
    internal class InspectorField_LayerBlendLayer : VisualElement {

        public InspectorField_InputPort portField; // 这部分不再显示在foldout下，而是在标题上，这里只是持有对象而不添加到内部
        public InspectorField_Layer layerField;

        public InspectorField_LayerBlendLayer() {
            portField = new() {
                name = "name-field",
                style = {
                    flexGrow = 1,
                }
            };
            //Add(portField);
        }

        public void EnableLayerField(bool enable) {
            if ((layerField != null) == enable) {
                return;
            }
            if (enable) {
                layerField = new();
                Add(layerField);
            } else {
                Remove(layerField);
                layerField = null;
            }
        }

    }

}
